#ifndef Serveur_h
#define Serveur_h

#include	"ActionListenner.cc"
#include	"WikiException.cc"
#include	"ServeurTCP.h"
#include	"ServeurUDP.h"
#include	"Utilisateur.h"
#include	"Categorie.h"
#include	"Groupe.h"

#include	<map>
#include	<string>

/*-------LISTE DES ACTIONS-------*/
#define	QUIT -1
#define	NO_INT 0
#define	MENU_ACCUEIL 1
	#define	REQU_INSCRIPTION_LOGIN 11
	#define	ERR_INSCRIPTION_LOGIN 110
		#define	REQU_INSCRIPTION_PASS 111
	#define	REQU_CONNEXION_LOGIN 12
	#define	ERR_CONNEXION_LOGIN 120
		#define	REQU_CONNEXION_PASS 121
		#define	ERR_CONNEXION_PASS 1210
#define MENU_ACCUEIL_LOG 2
	#define MENU_LECTURE_WIKI 21
		#define REQU_OUVRIR_CAT 211
		#define ERR_OUVRIR_CAT 2110
		#define REQU_CREER_CAT 212
		#define ERR_CREER_CAT 2120
		#define REQU_SUPPR_CAT 213
		#define ERR_SUPPR_CAT 2130
	#define MENU_GERER_GROUP 23
	#define MENU_ADMIN 24
	#define REQU_DECONNEXION 25

#define BROWSE_CAT 3
	#define REQU_OUVRIR_ART 31
	#define ERR_OUVRIR_ART 310
		#define READ_ART 311
			#define EDIT_ART 3111
	#define REQU_CREER_ART 32
	#define ERR_CREER_ART 320
	#define REQU_SUPPR_ART 33
	#define ERR_SUPPR_ART 330


using namespace std;

class Serveur : public ActionListenner
{
	private:
		ServeurTCP * communicateur;
		ServeurUDP * broadcast;
		/**
 	 	 * tableau des utilisateurs inscrits
 	 	 * index : nom
 	 	 * valeur : pointeur sur l'utilisateur
 	 	 */
		map<string,Utilisateur*> * utilisateurs;
		/**
 	 	 * tableau des categories
 	 	 * index : identifiant
 	 	 * valeur : pointeur sur la categorie
 	 	 */
		map<int,Categorie*> * categories;
		/**
 	 	 * tableau des groupes
 	 	 * index : identifiant
 	 	 * valeur : pointeur sur le groupe
 	 	 */
		map<int,Groupe*> * groupes;

		/**
 		 * Iterateurs de parcours utilises pour les getters
 		 * (initialises avec la fonction majIterateurs())
 		 */
		map<string,Utilisateur*>::iterator utilisateurs_it;
		map<int,Categorie*>::iterator categories_it;
		map<int,Groupe*>::iterator groupes_it;

		/**
 		 * Tableau de correspondance entre les clients connectes et les utilisateurs 
 		 * cle : descripteur du client (transmit par les methodes action() et getAction())
 		 * valeur : id utilisateur (-1) si non identifie
 		 */
		map<int,string> * utilisateursConnectes;

		/**
 		 * Tableau de variables de session associe a chaque client
 		 */
		map<int,map<string,string>*> * sessions;

	public:
		/**
 		 * Constructeur
 		 */
		Serveur();
		/**
 		 * Destructeur
 		 */
		~Serveur();

		/**
 		 * inititialise le communicateur et le broadcast
 		 */
		void initCommunication(int portCom, int portBroadcast, int tailleTampon);

		/**
 		 * Cree une nouvelle categorie
 		 * var nom : nom de la categorie
 		 * return : id de la categorie creee
 		 */
		int creerCategorie(string nom);

		/**
 		 * Supprime la categorie designee par l'id
 		 */
		void supprimerCategorie(int id);

		/**
 		 * Cree un nouveau utilisateur
 		 * var nom : nom de l'utilisateur
 		 * return : id de l'utilisateur cree (nom)
 		 */
		string creerUtilisateur(string nom);

		/**
 		 * Supprime l'utilisateur designee par l'id
 		 */
		void supprimerUtilisateur(string id);

		/**
 		 * Cree un nouveau groupe
 		 * var nom : nom du groupe
 		 * return : id du groupe cree
 		 */
		int creerGroupe(string nom);

		/**
 		 * Supprime le groupe designee par l'id
 		 */
		void supprimerGroupe(int id);

		/*-------ITERATEURS------*/
		/**
 		 * cree et fait pointer les iterateurs de parcours au debut de chaque vecteur
 		 */
		void majIterateurs();

		/*-------ACCESSEURS------*/


		/**
 		 * Retourne la categorie pointee par l'identifiant 
 		 * si id=-1, retourne la categorie pointee par l'iterateur categories_it et 
 		 * incremente l'iterateur.
 		 * Utiliser la methode majIterateurs() pour repartir au debut.
 		 * Utiliser "while(Categorie c = Serveur::getCategorie())" pour un parcours
 		 * de toutes les categories.
 		 */
		Categorie* getCategorie(int id = -1);

		/**
 		 * Retourne le groupe pointe par l'identifiant 
 		 * si id=-1, retourne le groupe pointe par l'iterateur groupes_it et 
 		 * incremente l'iterateur.
 		 * Utiliser la methode majIterateurs() pour repartir au debut.
 		 * Utiliser "while(Groupe c = Serveur::getGroupe())" pour un parcours
 		 * de tous les groupes.
 		 */
		Groupe* getGroupe(int id = -1);

		/**
 		 * Retourne le utilisateur pointe par l'identifiant 
 		 * si nom=NULL, retourne le utilisateur pointe par l'iterateur utilisateurs_it et 
 		 * incremente l'iterateur.
 		 * Utiliser la methode majIterateurs() pour repartir au debut.
 		 * Utiliser "while(Utilisateur c = Serveur::getUtilisateur())" pour un parcours
 		 * de toutes les utilisateurs.
 		 */
		Utilisateur* getUtilisateur(string nom = "");

		/*-------ACTIONLISTENNER-------*/
		/**
 		 * Fonction appelee par le communicateur apres reception de la reponse du client
 		 * Elle transmet la reponse du client et agit sur les donnees en fonction (creation d'article, ajout d'utilisateur...)
 		 * var numAction : numero de l'action associee a la reponse du client.
 		 * return : numero de la prochaine action
 		 */
		virtual int action(int numAction, string reponse, int descripteur);

		/**
 		 * Fonction appelee par le communicateur pour recuperer le message a envoyer au client afin qu'il reponde (en utilisant la methode action(int,string))
 		 * les message sont generalement des menus
 		 * var numAction : numero du message a envoyer
 		 * return : message a envoyer
 		 */
		virtual string getAction(int numAction, int descripteur);

	private:

		/**
 		 * retourne l'id de la categorie correspondant au nom saisi
 		 * return : id ou -1 si la categorie n'existe pas
 		 */
		int getCategorieId(string nom);

		/**
 		 * retourne l'id du groupe correspondant au nom saisi
 		 * return : id ou -1 si le groupe n'existe pas
 		 */
		int getGroupeId(string nom);


		/**
 		 * Initialise la session pour le descripteur
 		 * return : true si reussi, false si la session est deja demarree
 		 */
		bool sessionStart(int descripteur);

		/**
 		 * Detruit la session du descripteur
 		 * return : true si reussi, false si la session n'existe pas
 		 */
		bool sessionDestroy(int descripteur);

		/**
 		 * retourne la valeur de la variable de session
 		 * var descripteur : descripteur du client
 		 * var variable : nom de la variable
 		 * return : valeur de la variable ou NULL si le descripteur ou la variable n'est pas defini
 		 */
		string getVarSession(int descripteur, string variable);

		/**
 		 * Creer ou met a jour une variable de session
 		 * var descripteur : descripteur du client
 		 * var variable : nom de la variable
 		 * var valeur : valeur de la variable
 		 * return : true si reussi, false si le descripteur n'existe pas
 		 */
		bool setVarSession(int descripteur, string variable, string valeur);

		/**
 		 * Affiche le contenu des sessions
 		 * var descripteur (optionnel) : si precise affiche seulement la session du descripteur
 		 */
		void sessionPrint(int descripteur=-1);

		
		string categoriesToString();

};
#endif

